#include "bussiness.h"
#include <mutex>        //引用互斥锁操作

std::mutex valMutex;    //线程锁

//线程函数  供方法一测试  入参：待缓存的数据的空间地址
void* thread1(void* data)
{   
    //从传进来的数据地址中读取要缓存的cashData类型数据
    const cache::CCacheData data_ = *((cache::CCacheData*)data);

    //创建静态缓存（这样无论线程函数被执行多少次，缓存变量都只会被创建一次在堆区，当调用它的函数test_cache1销毁时，缓存变量和缓存区才会被销毁）
    static cache::CThreadVariable cThreadVariable;

    //打印线程id，打印过程需要上互斥锁，否则多线程同时抢占打印资源，会造成打印内容混乱
    valMutex.lock();
    pthread_t tid = pthread_self();
    printf("test_cache1()创建线程 %d 成功\n", (int)tid);
    valMutex.unlock();

    //哈希表空间探测并存储
    *(cThreadVariable.get_var()->m_pData) = data_;

    //打印存储效果
    valMutex.lock();
    int data1 = (cThreadVariable.get_var()->m_pData)->m_data_1;
    double data2 = (cThreadVariable.get_var()->m_pData)->m_data_2;
    std::string data3 = (cThreadVariable.get_var()->m_pData)->m_data_3;
    printf("存储数据: %d | %lf | %s 到缓存区成功",data1, data2, data3.c_str());
    printf("\n");
    printf("本次线程函数创建的堆区缓存，缓存区首地址是: %d", (int*)(cThreadVariable.get_SNodeAddress()));
    printf("\n");
    valMutex.unlock();
}

int test_cache1()
{   
    #define NUM_THREADS 10          //并发线程数量，修改此值来增加并发数量

    //1、创建线程id, 存储到tids数组中，后续要通过这个tids数组访问缓存的内容，线程id从0开始
    pthread_t tids[NUM_THREADS];

    //2、创建线程需要存储的数据
    cache::CCacheData data_list[NUM_THREADS];
    for(int i=0; i<NUM_THREADS; ++i)
    {
        data_list[i].m_data_1 = i;
        data_list[i].m_data_2 = i; 
        data_list[i].m_data_3 = "I am string";
    }
    
    //3、模拟多个线程并发缓存数据
    for(int i=0; i<NUM_THREADS; ++i)
    {
        int res = pthread_create(&tids[i], NULL, thread1, (void*)&data_list[i]);
        if (res){
            std::cout<<"test_cache1()创建线程 "<<tids[i]<<" 失败"<<std::endl;
            exit(-1);
        }
    }

    //4、等待所有线程结束
    for(int i=0; i<NUM_THREADS; ++i)
    {
        int res = pthread_join(tids[i], NULL);
        if (res){
            std::cout<<"test_cache1()结束线程 "<<tids[i]<<" 失败"<<std::endl;
            exit(-1);
        }
    }

    //5、通过tids查看刚刚通过并发线程缓存的数据，验证线程并发情况下缓存的效果是否正确（这里不做实现了，因为静态缓存是定义成了一个局部变量，不太好处理）
    //std::cout<<"test_cache1()创建的线程并发缓存成功, 通过线程id访问, 结果如下:"<<std::endl;
    /*
    for(int i=0; i<NUM_THREADS; ++i)
    {
        const cache::CCacheData = *(cThreadVariable.get_var()->m_pData);
        std::cout<<"线程 "<<tids[i]<< "缓存的数据是 "<<
    }*/
}

cache::CThreadVariable bussiness::CBussinessCache::m_cThreadVariable;   //静态变量要在类外初始化，这里不是定义一个全局变量，是完成静态成员的初始化
int test_cache2()
{
    //线程并发缓存的情景在方法一中已验证，这里不再模拟多线程操作，仅用一个主线程进行多次缓存
    //下面这段代码模拟10个业务对象依次进行缓存，每个对象都会覆盖前面
    for(int i = 0; i<10; ++i)
    {
        bussiness::CBussinessCache myBussiness; //每次循环都声明一个新的业务对象，业务对象调用内部方法进行数据缓存
        cache::CCacheData myData;
        myData.m_data_1 = i;
        myData.m_data_2 = i;
        myData.m_data_3 = "I am string";

        //获取上次缓存数据，多次调用缓存对象缓存数据时，缓存中存储的应当是上一次缓存的数据
        cache::CCacheData myDataTmp;
        if(1 == myBussiness.get_dataFromCache(myDataTmp))
            std::cout<<"当前缓存中的数据是："<<myDataTmp.m_data_1<<" | "<<myDataTmp.m_data_2<<" | "<<myDataTmp.m_data_3<<std::endl;
        else std::cout<<"当前缓存中的数据为空"<<std::endl;

        //缓存本次数据
        if(1 == myBussiness.story_dataIntoCache(myData))
            std::cout<<"更新数据到缓存中："<<myData.m_data_1<<" | "<<myData.m_data_2<<" | "<<myData.m_data_3<<std::endl;
        else std::cout<<"缓存本次数据失败"<<std::endl;
        std::cout<<"--------------------------------"<<std::endl;
    }
}

int main()
{   
    std::cout<<"测试方法一："<<std::endl;
    test_cache1();  //测试上文介绍的方法一

    std::cout<<"测试方法三："<<std::endl;
    test_cache2();  //测试上文介绍的方法三
}